﻿// Bravura : A music composition and audio synthesis framework.
//
// Copyright © 2011 Paul Vanukoff (pvanukoff@gmail.com)
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see http://www.gnu.org/licenses/.

using System;
using System.Collections.Generic;
using Bravura.Core.PluginLib;

namespace Bravura.Core.SynthLib
{
	/// <summary>
	/// Helper class which wraps an IAudioPlugin instance.
	/// </summary>
	internal class PluginProxy
	{
		#region Fields

		private Dictionary<int, AudioBuffer> _outputs = new Dictionary<int, AudioBuffer>();
		private Dictionary<int, AudioBuffer> _inputs = new Dictionary<int, AudioBuffer>();

		#endregion

		#region Public

		/// <summary>
		/// Get/set the wrapped plugin type.
		/// </summary>
		public Type Type
		{
			get;
			set;
		}

		/// <summary>
		/// Get/set the wrapped plugin instance.
		/// </summary>
		public IAudioPlugin Instance
		{
			get;
			set;
		}

		/// <summary>
		/// Zero out provisioned / connected outputs.
		/// </summary>
		public void ZeroOutputs(int count)
		{
			foreach (AudioBuffer buff in _outputs.Values)
			{
				buff.Zero(count);
			}
		}

		/// <summary>
		/// Zero out provisioned / connected inputs.
		/// </summary>
		public void ZeroInputs(int count)
		{
			foreach (AudioBuffer buff in _inputs.Values)
			{
				buff.Zero(count);
			}
		}

		/// <summary>
		/// Sets the gain of an input channel.
		/// </summary>
		public void SetInputGain(int channelNum, double gain)
		{
			_inputs[channelNum].SetGain(gain);
		}

		/// <summary>
		/// Sets the gain of an output channel.
		/// </summary>
		public void SetOutputGain(int channelNum, double gain)
		{
			_outputs[channelNum].SetGain(gain);
		}

		#endregion

		#region Private

		private void AssignOutput(int channelNum, AudioBuffer buffer)
		{
			_outputs[channelNum] = buffer;
			this.Instance.AssignOutputBuffer(channelNum, buffer);
		}

		private AudioBuffer GetOutput(int channelNum)
		{
			return _outputs.ContainsKey(channelNum) ? _outputs[channelNum] : null;
		}

		private void AssignInput(int channelNum, AudioBuffer buffer)
		{
			_inputs[channelNum] = buffer;
			this.Instance.AssignInputBuffer(channelNum, buffer);
		}

		private AudioBuffer GetInput(int channelNum)
		{
			return _inputs.ContainsKey(channelNum) ? _inputs[channelNum] : null;
		}

		#endregion

		#region Static

		/// <summary>
		/// Provision and connect plugin outputs and inputs.
		/// </summary>
		public static void Connect(PluginProxy source, int sourceChannel, PluginProxy target, int targetChannel)
		{
			// ensure the source / output is provisioned
			AudioBuffer srcBuff = source.GetOutput(sourceChannel);
			if (srcBuff == null)
			{
				srcBuff = new AudioBuffer();
				source.AssignOutput(sourceChannel, srcBuff);
			}

			// ensure the target / input is provisioned
			AudioBuffer tgtBuff = target.GetInput(targetChannel);
			if (tgtBuff == null)
			{
				tgtBuff = new AudioBuffer();
				target.AssignInput(targetChannel, tgtBuff);
			}

			// finally connect them
			if (srcBuff != null && tgtBuff != null)
			{
				srcBuff.Connect(tgtBuff);
			}
		}

		#endregion
	}
}
